﻿using System;
using System.Collections.Generic;
using System.Linq;
using CAION2.Properties;
using CAION2.ViewModels;

namespace CAION2.Classes
{
    static class ClassGameClass
    {
        private class CharacterStats
        {
            public byte Power;          //str
            public byte Health;         //vit
            public byte Agility;        //agi
            public byte Accuracy;       //acc
            public byte Knowledge;      //int
            public byte Will;           //wis
            public Double[] MpFactor;
            public Double[] HpFactor;
        }

        private static readonly Dictionary<int, string> Weapons = new Dictionary<int, string>();
        private static readonly Dictionary<string, List<int>> MainSlot;
        private static readonly Dictionary<string, List<int>> SubSlot;

        private static readonly Dictionary<int, string> Heads = new Dictionary<int, string>();
        private static readonly Dictionary<string, List<int>> HeadSlot;

        private static readonly Dictionary<int, string> TLFSGs = new Dictionary<int, string>();
        private static readonly Dictionary<string, List<int>> TLFSGsSlots;
        
        private static readonly Dictionary<string, CharacterStats> ClassStats = new Dictionary<string, CharacterStats>(); 

        static ClassGameClass()
        {
            #region Weapons

            Weapons = new Dictionary<int, string>
                {
                    {1, "1h_dagger"},
                    {2, "1h_gun"},
                    {3, "1h_mace"},
                    {4, "1h_sword"},
                    {5, "2h_book"},
                    {6, "2h_cannon"},
                    {7, "2h_harp"},
                    {8, "2h_orb"},
                    {9, "2h_polearm"},
                    {10, "2h_staff"},
                    {11, "2h_sword"},
                    {12, "bow"},
                    {13, "shield"},
                    {14, "2h_keyblade"}
                };

            #endregion
            
            #region Main slot

            MainSlot = new Dictionary<string, List<int>>
                {
                    {Resources.Class_Fighter, new List<int> {11, 4, 3, 9, 12, 1}},
                    {Resources.Class_Knight, new List<int> {11, 4, 3}},

                    {Resources.Class_Assassin, new List<int> {1, 4}},
                    {Resources.Class_Ranger, new List<int> {1, 12}},

                    {Resources.Class_Wizard, new List<int> {5, 8}},
                    {Resources.Class_Elementalist, new List<int> {5, 8}},

                    {Resources.Class_Priest, new List<int> {10, 3}},
                    {Resources.Class_Chanter, new List<int> {10, 3}},
                    
                    {Resources.Class_Gunner, new List<int> {2, 6}},
                    {Resources.Class_Rider, new List<int> {2, 14}},
                    
                    {Resources.Class_Bard, new List<int> {7}}
                };

            #endregion

            #region Sub slot

            SubSlot = new Dictionary<string, List<int>>
                {
                    {Resources.Class_Fighter, new List<int> {13, 1, 4, 3}},
                    {Resources.Class_Knight, new List<int> {13}},

                    {Resources.Class_Assassin, new List<int> {1, 4}},
                    {Resources.Class_Ranger, new List<int> {1}},

                    {Resources.Class_Wizard, new List<int> {}},
                    {Resources.Class_Elementalist, new List<int> {}},

                    {Resources.Class_Priest, new List<int> {13}},
                    {Resources.Class_Chanter, new List<int> {13}},

                    {Resources.Class_Gunner, new List<int> {2}},
                    {Resources.Class_Rider, new List<int> {}},

                    {Resources.Class_Bard, new List<int> {}},
                };

            #endregion


            #region Heads

            Heads = new Dictionary<int, string>
                {
                    {1, "ch_head"},  //кальчуга
                    {2, "lt_head"},  //кожа
                    {3, "pl_head"},  //латы
                    {4, "rb_head"},  //ткань
                    {5, "ac_head"}   
                };

            #endregion
            
            #region Head Slot

            // Здесь указывается то что они НЕ носят!!!
            HeadSlot = new Dictionary<string, List<int>>
                {
                    {Resources.Class_Fighter, new List<int> {}},
                    {Resources.Class_Knight, new List<int> {}},

                    {Resources.Class_Assassin, new List<int> {1, 3}},
                    {Resources.Class_Ranger, new List<int> {1, 3}},

                    {Resources.Class_Wizard, new List<int> {1, 2, 3}},
                    {Resources.Class_Elementalist, new List<int> {1, 2, 3}},

                    {Resources.Class_Priest, new List<int> {3}},
                    {Resources.Class_Chanter, new List<int> {3}},
                    
                    {Resources.Class_Gunner, new List<int> {1, 3}},
                    {Resources.Class_Rider, new List<int> {3}},

                    {Resources.Class_Bard, new List<int> {1, 2, 3}},
                };

            #endregion
            
            #region Torso Legs Foot Shoulder Glove

            TLFSGs = new Dictionary<int, string>
                {
                    {0, "clothes"}, //одежда
                    {1, "robe"},    //ткань
                    {2, "leather"}, //кожа
                    {3, "chain"},   //кальчуга
                    {4, "plate"}    //латы
                };

            #endregion

            #region Torso Legs FootvShoulder Glove Slots
            
            TLFSGsSlots = new Dictionary<string, List<int>>
                {
                    //эти все носят!!
                    {Resources.Class_Fighter, new List<int> {}},
                    {Resources.Class_Knight, new List<int> {}},

                    {Resources.Class_Assassin, new List<int> {0, 1, 2}},
                    {Resources.Class_Ranger, new List<int> {0, 1, 2}},

                    {Resources.Class_Wizard, new List<int> {0, 1}},
                    {Resources.Class_Elementalist, new List<int> {0, 1}},

                    {Resources.Class_Priest, new List<int> {0, 1, 2, 3}},
                    {Resources.Class_Chanter, new List<int> {0, 1, 2, 3}},

                    {Resources.Class_Gunner, new List<int> {0, 1, 2}},
                    {Resources.Class_Rider, new List<int> {1, 2, 3}},

                    {Resources.Class_Bard, new List<int> {0, 1}}
                };

            #endregion

            #region Characters Stats

            ClassStats = new Dictionary<string, CharacterStats>();
            CharacterStats stats = new CharacterStats
                {
                    Power = 115,
                    Health = 115,
                    Accuracy = 100,
                    Agility = 100,
                    Knowledge = 90,
                    Will = 90,
                    MpFactor = new[] {0.005, 70, 100},
                    HpFactor = new[] {1.265, 47.3, 286}
                };
            ClassStats.Add(Resources.Class_Fighter, stats);

            stats = new CharacterStats
                {
                    Power = 115,
                    Health = 100,
                    Accuracy = 100,
                    Agility = 100,
                    Knowledge = 90,
                    Will = 105,
                    MpFactor = new[] {0.005, 70, 160},
                    HpFactor = new[] {1.3225, 49.45, 230}
                };
            ClassStats.Add(Resources.Class_Knight, stats);

            stats = new CharacterStats
                {
                    Power = 110,
                    Health = 100,
                    Accuracy = 110,
                    Agility = 110,
                    Knowledge = 90,
                    Will = 90,
                    MpFactor = new[] {0.005, 70, 100},
                    HpFactor = new[] {1.035, 38.7, 180}
                };
            ClassStats.Add(Resources.Class_Assassin, stats);

            stats = new CharacterStats
                {
                    Power = 100,
                    Health = 100,
                    Accuracy = 115,
                    Agility = 115,
                    Knowledge = 90,
                    Will = 90,
                    MpFactor = new[] {0.005, 70, 100},
                    HpFactor = new[] {0.805, 30.1, 140}
                };
            ClassStats.Add(Resources.Class_Ranger, stats);

            stats = new CharacterStats
                {
                    Power = 90,
                    Health = 90,
                    Accuracy = 100,
                    Agility = 100,
                    Knowledge = 120,
                    Will = 110,
                    MpFactor = new[] {0.0075, 105, 270},
                    HpFactor = new[] {0.74625, 28.075, 101}
                };
            ClassStats.Add(Resources.Class_Wizard, stats);

            stats = new CharacterStats
                {
                    Power = 90,
                    Health = 90,
                    Accuracy = 100,
                    Agility = 100,
                    Knowledge = 115,
                    Will = 115,
                    MpFactor = new[] {0.0075, 105, 300},
                    HpFactor = new[] {0.805, 30.1, 112}
                };
            ClassStats.Add(Resources.Class_Elementalist, stats);

            stats = new CharacterStats
                {
                    Power = 105,
                    Health = 110,
                    Accuracy = 90,
                    Agility = 90,
                    Knowledge = 105,
                    Will = 110,
                    MpFactor = new[] {0.0075, 105, 207},
                    HpFactor = new[] {0.92, 34.4, 192}
                };
            ClassStats.Add(Resources.Class_Priest, stats);

            stats = new CharacterStats
                {
                    Power = 110,
                    Health = 105,
                    Accuracy = 90,
                    Agility = 90,
                    Knowledge = 105,
                    Will = 110,
                    MpFactor = new[] {0.0075, 105, 207},
                    HpFactor = new[] {0.035, 38.7, 198}
                };
            ClassStats.Add(Resources.Class_Chanter, stats);

            stats = new CharacterStats
                {
                    Power = 90,
                    Health = 100,
                    Accuracy = 100,
                    Agility = 100,
                    Knowledge = 110,
                    Will = 110,
                    MpFactor = new[] {0.00625, 91.025, 233},
                    HpFactor = new[] {0.92, 34.4, 160}
                };
            ClassStats.Add(Resources.Class_Bard, stats);

            stats = new CharacterStats
                {
                    Power = 100,
                    Health = 105,
                    Accuracy = 100,
                    Agility = 105,
                    Knowledge = 100,
                    Will = 100,
                    MpFactor = new[] {0.005, 70, 140},
                    HpFactor = new[] {1.035, 38.7, 198}
                };
            ClassStats.Add(Resources.Class_Gunner, stats);

            stats = new CharacterStats
            {
                Power = 100,
                Health = 100,
                Accuracy = 100,
                Agility = 100,
                Knowledge = 105,
                Will = 105,
                MpFactor = new[] { 0.01, 83.7, 197 },
                HpFactor = new[] { 1.215, 44.55, 221 }
            };
            ClassStats.Add(Resources.Class_Rider, stats);

            #endregion
            
        }
        
        public static string GetGameClassConditionForPlace(string className, ItemPlaceViewModel.EquipmentSlots slot, string[] masterItem)
        {
            string condition = "";

            switch (slot)
            {
                case ItemPlaceViewModel.EquipmentSlots.Main:
                    condition = "equipment_slots LIKE '%main%' AND ";
                    condition += MainSlot[className].Aggregate("weapon_type IN (", (current, code) => current + string.Format("'{0}',", Weapons[code]));
                    if (!string.IsNullOrEmpty(condition)) condition = condition.Substring(0, condition.Length - 1) + ")";
                    break;

                case ItemPlaceViewModel.EquipmentSlots.Armsfused:
                    if (masterItem != null && masterItem.Any())
                    {
                        condition = string.Format("equipment_slots LIKE '%main%' AND weapon_type = '{0}' AND level <= {1}", masterItem[0], masterItem[1]);
                    }
                    break;

                case ItemPlaceViewModel.EquipmentSlots.Sub:
                    if (SubSlot[className].Count > 0)
                    {
                        condition = "equipment_slots LIKE '%sub%' AND (";
                        condition += SubSlot[className].Aggregate("weapon_type IN (", (current, code) => current + string.Format("'{0}',", Weapons[code]));
                        condition = condition.Substring(0, condition.Length - 1) + ")";
                        if (SubSlot[className].Contains(13))
                        {
                            condition += " OR name LIKE '%shield%'";
                        }
                        condition += ")";
                    }
                    break;

                case ItemPlaceViewModel.EquipmentSlots.Head:
                    if (HeadSlot[className].Count > 0)
                    {
                        condition = HeadSlot[className].Aggregate("(", (current, code) => current + ("name NOT LIKE '%" + Heads[code] + "%' AND "));
                        condition = condition.Substring(0, condition.Length - 4) + ")";
                    }
                    break;

                case ItemPlaceViewModel.EquipmentSlots.Torso:
                case ItemPlaceViewModel.EquipmentSlots.Leg:
                case ItemPlaceViewModel.EquipmentSlots.Foot:
                case ItemPlaceViewModel.EquipmentSlots.Shoulder:
                case ItemPlaceViewModel.EquipmentSlots.Glove:
                    if (TLFSGsSlots[className].Count > 0)
                    {
                        condition = TLFSGsSlots[className].Aggregate("(", (current, code) => current + ("armor_type = '" + TLFSGs[code] + "' OR "));
                        condition = condition.Substring(0, condition.Length - 4) + ")";
                    }
                    break;
            }

            return condition;
        }

        public static bool GetEnableForSubSlotPlace(string className)
        {
            return SubSlot[className].Count != 0;
        }

        public static bool CheckItemForSlot(string className, ItemPlaceViewModel.EquipmentSlots slot, string weaponType = "", string armorType = "", string name = "")
        {
            switch (slot)
            {
                case ItemPlaceViewModel.EquipmentSlots.Main:
                    return !MainSlot[className].Contains(Weapons.First(w => w.Value == weaponType).Key);

                case ItemPlaceViewModel.EquipmentSlots.Sub:
                    if (string.IsNullOrEmpty(weaponType))
                    {
                        return !SubSlot[className].Contains(13);
                    }
                    return !SubSlot[className].Contains(Weapons.First(w => w.Value == weaponType).Key);

                case ItemPlaceViewModel.EquipmentSlots.Head:
                    return HeadSlot[className].Contains(Heads.First(w => w.Value == name).Key);
               
                case ItemPlaceViewModel.EquipmentSlots.Torso:
                case ItemPlaceViewModel.EquipmentSlots.Leg:
                case ItemPlaceViewModel.EquipmentSlots.Foot:
                case ItemPlaceViewModel.EquipmentSlots.Shoulder:
                case ItemPlaceViewModel.EquipmentSlots.Glove:
                    if (!TLFSGsSlots[className].Any()) return false;
                    if (string.IsNullOrEmpty(armorType)) return false;
                    return !TLFSGsSlots[className].Contains(TLFSGs.First(w => w.Value == armorType).Key);
                default:
                    return false;
            }
        }

        public static Single GetClassStatValue(string statName, string gameClass, byte characterLevel)
        {
            switch (statName)
            {
                case "maxhp":
                    return (int)Math.Floor(characterLevel * characterLevel * (Single)ClassStats[gameClass].HpFactor[0] 
                                            + characterLevel * (Single)ClassStats[gameClass].HpFactor[1]
                                            + (Single)ClassStats[gameClass].HpFactor[2]);
               
                case "maxmp":
                    return (int)Math.Floor(characterLevel * characterLevel * (Single)ClassStats[gameClass].MpFactor[0]
                                            + characterLevel * (Single)ClassStats[gameClass].MpFactor[1]
                                            + (Single)ClassStats[gameClass].MpFactor[2]);

                case "phyattack":
                    return (int)Math.Floor(18 * (Single)ClassStats[gameClass].Power/100);
                
                case "maxfp":
                    return 60;

                case "attackdelay":
                    return 1.5f;

                case "boostcastingtime":
                    return 1.0f;

                case "speed":
                    return 6.0f;

                case "flyspeed":
                    return 9.0f;

                case "magicalhitaccuracy":
                    return (int)Math.Floor(characterLevel*14.25);
                    
                case "hitaccuracy":
                    return (int)Math.Floor((Single)ClassStats[gameClass].Accuracy * 2 + 8 * characterLevel - 10);
                    
                case "dodge":
                case "parry":
                case "block":
                    return (int)Math.Floor((Single)ClassStats[gameClass].Agility * 3.1 + 12.4 * characterLevel - 248);

                case "magicalcriticalreducerate":
                    if (gameClass == Resources.Class_Priest
                        || gameClass == Resources.Class_Wizard
                        || gameClass == Resources.Class_Elementalist
                        || gameClass == Resources.Class_Bard)
                    {
                        return 50;
                    }
                    return 0;

                case "magicalcritical":
                    return 50;

                case "critical":
                    if (gameClass == Resources.Class_Priest
                        || gameClass == Resources.Class_Chanter)
                    {
                        return 1;
                    }
                    if (gameClass == Resources.Class_Assassin
                        || gameClass == Resources.Class_Ranger)
                    {
                        return 3;
                    }
                    return 2;

                case "physicalcriticalreducerate":
                    return Math.Max(0, (characterLevel-50)*6);

                default:
                    return 0;
            }
        }

        public static byte GetPower(string gameClass)
        {
            return ClassStats[gameClass].Power;
        }

        public static string GetGameClassNameForFileName(string gameClass)
        {
            if (gameClass == Resources.Class_Fighter) return "Profile_Fighter";
            if (gameClass == Resources.Class_Knight) return "Profile_Knight";

            if (gameClass == Resources.Class_Assassin) return "Profile_Assassin";
            if (gameClass == Resources.Class_Ranger) return "Profile_Ranger";

            if (gameClass == Resources.Class_Wizard) return "Profile_Wizard";
            if (gameClass == Resources.Class_Elementalist) return "Profile_Elementalist";

            if (gameClass == Resources.Class_Priest) return "Profile_Priest";
            if (gameClass == Resources.Class_Chanter) return "Profile_Chanter";

            if (gameClass == Resources.Class_Rider) return "Profile_Rider";
            if (gameClass == Resources.Class_Gunner) return "Profile_Gunner";

            if (gameClass == Resources.Class_Bard) return "Profile_Bard";

            return "Profile";
        }

        public static string GetGameClassNameForProfileFile(string gameClass)
        {
            if (gameClass == Resources.Class_Fighter) return "Fighter";
            if (gameClass == Resources.Class_Knight) return "Knight";

            if (gameClass == Resources.Class_Assassin) return "Assassin";
            if (gameClass == Resources.Class_Ranger) return "Ranger";

            if (gameClass == Resources.Class_Wizard) return "Wizard";
            if (gameClass == Resources.Class_Elementalist) return "Elementalist";

            if (gameClass == Resources.Class_Priest) return "Priest";
            if (gameClass == Resources.Class_Chanter) return "Chanter";

            if (gameClass == Resources.Class_Rider) return "Rider";
            if (gameClass == Resources.Class_Gunner) return "Gunner";

            if (gameClass == Resources.Class_Bard) return "Bard";

            return "";
        }

        public static string GetGameClassNameFromProfileFile(string profileGameClass)
        {
            if (profileGameClass == "Fighter") return Resources.Class_Fighter;
            if (profileGameClass == "Knight") return Resources.Class_Knight;

            if (profileGameClass == "Assassin") return Resources.Class_Assassin;
            if (profileGameClass == "Ranger") return Resources.Class_Ranger;

            if (profileGameClass == "Wizard") return Resources.Class_Wizard;
            if (profileGameClass == "Elementalist") return Resources.Class_Elementalist;

            if (profileGameClass == "Priest") return Resources.Class_Priest;
            if (profileGameClass == "Chanter") return Resources.Class_Chanter;

            if (profileGameClass == "Rider") return Resources.Class_Rider;
            if (profileGameClass == "Gunner") return Resources.Class_Gunner;

            if (profileGameClass == "Bard") return Resources.Class_Bard;

            return "";
        }
        
        public static string GetGameClassFieldNameFromClassName(string className)
        {
            if (className == Resources.Class_Fighter) return "fighter";
            if (className == Resources.Class_Knight) return "knight";

            if (className == Resources.Class_Assassin) return "assassin";
            if (className == Resources.Class_Ranger) return "ranger";

            if (className == Resources.Class_Wizard) return "wizard";
            if (className == Resources.Class_Elementalist) return "elementalist";

            if (className == Resources.Class_Priest) return "priest";
            if (className == Resources.Class_Chanter) return "chanter";

            if (className == Resources.Class_Rider) return "rider";
            if (className == Resources.Class_Gunner) return "gunner";

            if (className == Resources.Class_Bard) return "bard";

            return "";
        }
    }
}
 

